import controlP5.*;


int numFilms = 1600;
int year0 = 1975;
int year1 = 1980;
int pop0 = 30;
int pop1 = 90;
int len0=90;
int len1=120;
boolean togglePOP= true;
int Maxpop,Minpop,MaxLen,MinLen,MaxYear,MinYear;
film[] filmsArray = new film[numFilms];
ArrayList<film> filmList; 
ArrayList<String> filmCategory;
HashMap<String, categ> Categs ;
PFont font = createFont("Helvetica-Bold", 15);
//***********  sliders part
int bars = 2;

VSlider Vslider [];
HSlider Hslider [];
VSlider Vslider_ [];
ColorScheme global_cs = new ColorScheme();
//***********  sliders part

//GraphPart
ControlP5 cp5;
GraphControls gcs;
ColorPicker cpi=null;
boolean drawingGraph=false;
//boolean colorPaletteOpen=false;
GraphType gTypePOP=new GraphType(GraphType.POPULARITY);
GraphType gTypeLEN=new GraphType(GraphType.LENGTH);

//GraphPart

//networks part
ParticleEngine engine;
Particle lastParticle = null;
Particle pressed;
String filmName ;
int cac=0, cacs=0, cd=0;
boolean displayingFilm=false;

//netowrk part

void setup(){
  size(1280, 700);
  frameRate(60);
  smooth();
  readData();
  setVars();
  setElmts(); 

  //***********  sliders part
  Vslider_ = new VSlider[bars];
  Vslider = new VSlider[bars];
  Hslider = new HSlider[bars];
  //lengthSlider
  Vslider_[0] = new VSlider(width-50, (int)height/4+200, 16, 136);
  Vslider_[1] = new VSlider(width-50+16, (int)height/4+200 , 16, 136);
  //popSlider
  Vslider[0] = new VSlider(width-50, (int)height/4, 16, 116);
  Vslider[1] = new VSlider(width-50+16, (int)height/4, 16, 116);
  //yearSlider
  Hslider[0] = new HSlider(40, height-30-16, 90, 16);
  Hslider[1] = new HSlider(40, height-30, 90, 16);
  // Set the initial slider values 
    Vslider_[0].setValue(0.75);
    Vslider_[1].setValue(1);
    
    Vslider[0].setValue(0.3);
    Vslider[1].setValue(0.9);
    
    Hslider[0].setValue(0.66);
    Hslider[1].setValue(0.72);
//***********  sliders part

//GraphPart

cp5=new ControlP5(this);
gcs=new GraphControls(width-900, 20,cp5,Categs);
                  cpi=new ColorPicker(gcs.getColorPickerPositionX(),gcs.getColorPickerPositionY()+30);
                  cpi.closeColorPicker();


}

//******** toggle button code

void drawCloseButton(){
  int r,g,b;
  String t;

  r=0; g=240; b=119;

  
  fill(r,g,b);
  rect(130, 350, 100, 30);
  fill(250);
  text("Close", 180, 372);
}

//******** toggle button code 

void drawButton(boolean bo){
  int r,g,b;
  String t;
  if(bo){
  t="Popularity Toggled";
  r=200; g=130; b=120;
gcs.changeType(gTypePOP);
  } else {t="Length Toggled";
  r=100; g=200; b=50;
  gcs.changeType(gTypeLEN);
}
  
  fill(r,g,b);
  rect(width-130, height-50, 100, 30);
  fill(250);
  text(t, width-80, height-32);
}

//************ Button pressed 
void buttonPressed(){
  if( mouseX  >=  width-130 && mouseX<= width-30 && mouseY <= height-20 && mouseY>= height-50 )
  togglePOP = !togglePOP;
   drawButton(togglePOP);
}

//************ Button pressed 

//*************** Interaction 

void mousePressed(){
  
  if(mousePressed && mouseButton == LEFT){  
    if(displayingFilm)
    {//  rect(130, 350, 100, 30);
      line(230,380,130,350);
      line(230,350,130,380);
      if(mouseX<=230 && mouseX>=130 && mouseY<=380 &&mouseY>=350)
        displayingFilm=false;
      return;
    }
    buttonPressed();
        int i=0;
        boolean stop=false;
        while(!stop && i<filmList.size()){
          stop = filmList.get(i).ball.testHighlighted(mouseX,mouseY);
          i++;          
        } 
  }
 }

//*************** Interaction 

//****** update values
boolean  updateScales(){
  int y0=year0;
  int y1=year1;
  int p0=pop0;
  int p1=pop1;
  int l0=len0;
  int l1=len1;
  year0 = Hslider[0].getValue();
  year1 = Hslider[1].getValue();
  pop0 = Vslider[0].getValue();
  pop1 = Vslider[1].getValue();
  len0 = Vslider_[0].getValue();
  len1 = Vslider_[1].getValue();
  
  if( y0!=year0 || y1!=year1 || l0!=len0 || l1!=len1 || p0!=pop0 || p1!=pop1 ) return true;
  else return false;
}
   //****** update values 

//***********  draw 

void draw() {
  background(0);
  drawButton(togglePOP);
  if(updateScales()){
  setVars();
  setElmts();
 } 
     // draw clusters
  for (int i = 0; i < clusters.size(); i++) {
     
    // positioning algorithm     
    float col = i % CR[0];
    float row = floor(i / CR[0]);
     
    float posX = colWidth * col + colWidth/2;
    float posY = rowHeight * row + rowHeight/2;
     
    clusters.get(i).position(posX, posY);
    clusters.get(i).display();
    
    if(clusters.get(i).displayFilm)
    {
      filmName=clusters.get(i).filmName;
      displayingFilm=true;
      clusters.get(i).displayFilm=false;
      engine = new ParticleEngine();
      createParticles(filmName); // PASS TO THIS FUNCTION THE NAME OF THE FILM CLICKED
      engine.update();
     //               engine = new ParticleEngine();
//  filmName=filmsArray[0].title; //COMMENT THIS
//  createParticles(filmName); // PASS TO THIS FUNCTION THE NAME OF THE FILM CLICKED
//  engine.update();
    }
  }
  if(displayingFilm)
  {
    
    fill(0,0,0);
    rect(0,0,width,height);
   // colorMode(RGB);
    engine.draw();
    drawCloseButton();
  }
  else{
  // draw sliders
    fill(140,162,165);
   textAlign(CENTER);
   textFont(font);
   textSize(12);
  text("Popularity", width-50, (int)height/4-20);
  text("Year",150 , height-30-26);
  text("Length", width-50, (int)height/4+180);
  for (int i=0; i<bars; i++) {
        fill(140,162,165);
   textAlign(CENTER);
   textFont(font);
   textSize(10);
    text(" " + Hslider[i].getValue(), 150, height-36+i*16);
    text(" " + Vslider[i].getValue(), width-50+i*16, (int)height/4-8);
    text(" " + Vslider_[i].getValue(), width-50+i*16, (int)height/4+198);
    // Sliders/sliders and buttons updates and displaying
    Vslider[i].update();
    Vslider[i].display();

    Hslider[i].update();
    Hslider[i].display();
    
    Vslider_[i].update();
    Vslider_[i].display();
  }
  }
  gcs.draw();
  if(cpi!=null)
  {
  cpi.Draw();
  if(cpi.open==false)
    gcs.changeColor(cpi.getColor());
  }
  
  
}

//*********** draw 

//********* set graphic elements
float damping = 0.09;
int[] CR;
float colWidth;
float rowHeight;
 
ArrayList<Cluster> clusters ;
ArrayList<Ball> balls; 

void initializeBalls(){
    balls= new ArrayList<Ball>(); 
    for (int i = 0; i < filmList.size(); i++) {
      filmList.get(i).setBall(new Ball(i, width/2, height/2, filmList.get(i).title ,filmList.get(i)  )   , i);  
        balls.add(filmList.get(i).ball);
       
    }
        println("\n \n balls created ."+filmList.size());

}

void initializeClusters(){
  clusters = new ArrayList<Cluster>();
  for(int i = 0 ;i<filmCategory.size();++i){
    String s = filmCategory.get(i);
    categ c = (categ) Categs.get(s);
    Ball[] blist = c.toBallsArray();
    clusters.add(new Cluster(i,  blist , s));
    for(int j=0;j<blist.length;++j){
    blist[j].setCluster(clusters.get(i));
    }
    println("\n \n cluster."+s+" created ");
  }
 
}

//////////////////////////////////////////////////forgraphControls
void controlEvent(ControlEvent theEvent) {
  try{
  if (theEvent.isGroup()) {
    // check if the Event was triggered from a ControlGroup
    println(theEvent.group().value()+" from "+theEvent.group());
    if(theEvent.group().name().equals("validate")){
//      ListBoxItem selectedItem = dropdown.getItem((int)theEvent.value());
//      if(selectedItem.getName().equals("item 3")){
//        println("item 3 clicked... do something here!");
//      }
//      else if(selectedItem.getName().equals("item 4")){
//        println("item 4 clicked... do something here!");
//      }
        println("validated");
    }
  } else if(theEvent.isController()) {
    println(theEvent.controller().value()+" from "+theEvent.controller()); 
        if(theEvent.controller().name().equals("Add")){
          drawingGraph=true;
          println("add");
          String catSel;
          int sizeSel;
          catSel=gcs.dropDownCateg.getItem((int)gcs.dropDownCateg.value()).getName();
          sizeSel=gcs.dropDownSizes.getItem((int)gcs.dropDownSizes.value()).getValue();
          println(catSel);
          println(sizeSel);
          int wg,hg;
          switch(sizeSel)
          {
            
            case 0: wg=800; hg=600;
            break;
            case 1: wg=700; hg=480;
            break;
            case 2: wg=400; hg=300;
            break;
            case 3: wg=320; hg=180;
            break;
            default:
            wg=200; hg=200;
            break;
          }
          println(wg,hg);
          color gColColor;
          if(cpi.picked!=-1) gColColor=cpi.picked;
          else gColColor=color(255,0,0);
          
          if(togglePOP)
          gcs.addGraph(catSel,wg,hg,cpi.picked,new GraphType(GraphType.POPULARITY));
          else
          gcs.addGraph(catSel,wg,hg,cpi.picked,new GraphType(GraphType.LENGTH));
          
          drawingGraph=false;
        }
                if(theEvent.controller().name().equals("color")){


                    cpi.openColorPicker();

                  
              
        }
        if(theEvent.controller().name().equals("Hide/Show")){
          gcs.drawGraph=!gcs.drawGraph;
          
        }
  }
  }
  catch (Exception e)
  {
    println("This is a good visualisation");
  }
}
////////////////////////////////////////////////////////////////////////



void setElmts(){
  if(!drawingGraph)
  {
    CR= new int[2];
    CR = getCR(Categs.size(),4);  // 4 number of layers per cluster
    colWidth = width/CR[0];
    rowHeight = height/CR[1];
    println(CR[0]+ "   "+ CR[1]+"  ");
    // initialize ball objects
    initializeBalls(); 
    initializeClusters();
  }
}
//*****1**** set graphic elements

//********** set vars
void setVars(){
   println(Maxpop+" "+Minpop+" "+MaxYear+" "+MinYear+" "+MaxLen+" "+MinLen);
    
    applyFilters();
    getCategoryNum();
    printList();
    createCategs();
    for (String s : filmCategory){  
      categ c = (categ) Categs.get(s);
     println("."+c.subject+" " + c.size());
      for(film f : c.films){
        println(".........."+f.toString());
      }
 }

    

}
//********** set vars


//********** readData
void readData() {
   Maxpop=0;
   Minpop=90;
   MinLen=300;
   MaxLen=0;
   MaxYear=0;
   MinYear=2017;
    String[] lines = loadStrings("http://www.infres.enst.fr/~eagan/class/as2014/inf229/data/film.csv");
    for (int i = 2; i < numFilms+2; ++i) {
    String pieces[] = split(lines[i], ';');
    filmsArray[i-2] = new film(i-2,int(pieces[0]),int(pieces[1]),pieces[2],pieces[3],new actor("M",pieces[4]),new actor("F",pieces[5])
    ,new director(pieces[6]),int(pieces[7]),boolean(pieces[8].equals("Yes")?1:0),pieces[9]);
    if(filmsArray[i-2].year>MaxYear)MaxYear=filmsArray[i-2].year;
    if(filmsArray[i-2].year<MinYear)MinYear=filmsArray[i-2].year;
    if(filmsArray[i-2].popularity>Maxpop)Maxpop=filmsArray[i-2].popularity;
    if(filmsArray[i-2].popularity<Minpop)Minpop=filmsArray[i-2].popularity;
    if(filmsArray[i-2].popularity>MaxLen)MaxLen=filmsArray[i-2].leng;
    if(filmsArray[i-2].popularity<MinLen)MinLen=filmsArray[i-2].leng;
    }
 
}  

void printList(){
  println("/-----------------------------------------------------------------------");
 for(int i=0; i< filmList.size();i++){
    println(filmList.get(i).toString());
    } 
    println("**************"+filmList.size());
}
//********** readData


//****** filtering code 

void applyFilters(){
  filmList = new ArrayList<film>();
 for(int i =0;i< filmsArray.length;++i){
  if((filmsArray[i].year<=year1 && filmsArray[i].year>=year0 ) && (filmsArray[i].popularity<=pop1 && filmsArray[i].popularity>=pop0) 
 && (filmsArray[i].leng<=len1 && filmsArray[i].leng>=len0) ){
      filmList.add(filmsArray[i]);
  }
 } 
}

//****** filtering code 


//****** Genre numb

void getCategoryNum() {
  filmCategory = new ArrayList<String>();
  filmCategory.add((filmList.get(0)).subject);
  for (int i = 1; i < filmList.size(); i++) {
    boolean stop = false;
    int j = 0;
    while (!stop && j < filmCategory.size()) {
      if (((filmList.get(i)).subject).equals(filmCategory.get(j))) stop=true;
      else j++;
    }  
     if ((stop == false) && !(((filmList.get(i)).subject).equals(""))) filmCategory.add((filmList.get(i)).subject);
     
    }
    for (int i = 0; i < filmCategory.size(); i++) println(filmCategory.get(i));
}


//****** Genre numb


//****** create Categories 
void createCategs(){
  Categs = new HashMap<String, categ>();
 for (String s : filmCategory){  
  Categs.put(s,new categ(s));
 } 
 for(film f : filmList) {
  categ c = (categ) Categs.get(f.subject); 
  c.films.add(f);
 }
}
//****** create Categories 



//***** column & row 
int[] getCR(int n,int q){
int[] CR= new int[2];
int a=1;
int b=1;
  while (a*b<n){
    int a1=a;
    int b1=b;
    if(a*b==n) {break;}
     if((a+1)*b<=n){a++;}
     if (a*(b+1)<=n){b++;} 
     if(a==a1 && b==b1)break;
  }
  if(a*b!=n){
    if(a<=b) a++;
    else b++;
  } 
  CR[0]=a;
  CR[1]=b;
  return CR;
}
//***** column & row 

//networks

void createParticles(String filmTitle){
  cac=0;
  cacs=0;
  cd=0;
  engine.clearAll();
  actor ac=null, acs=null;
  director d=null;
  Particle pac, pacs, pd;
  
  for(int i=0; i<numFilms; i++){
    if(filmsArray[i].title.equals(filmTitle)){
      ac=new actor(filmsArray[i].ac);
      acs=new actor(filmsArray[i].acs);
      d=new director(filmsArray[i].dir);
      break;
    }
  }
  //create particles CENTRAL
  if(ac!=null && acs!=null && d!=null){
    pac = new Particle(ac.name, 0, width/2, height/4 /*(2*width)/3, (7*height)/12 */);
    pac.clicked = true;
    engine.addParticle(pac, 0); 
    pacs = new Particle(acs.name, 1,  width/2, height*3/4 /*(width)/3, (7*height)/12*/ );
    pacs.clicked = true;
    engine.addParticle(pacs, 1);
    pd = new Particle(d.name, 2, width/2, height/2 /*(width)/2, (5*height)/12*/);
    pd.clicked = true;
    engine.addParticle(pd, 2);
    
    engine.connectParticles(pac.label, pacs.label, 0, 1);
    engine.connectParticles(pac.label, pd.label, 0, 2);
    engine.connectParticles(pacs.label, pd.label, 1, 2);
    
  }
  
  //create springs
  for(int i=0; i<numFilms; i++){
    
    if( !filmsArray[i].title.equals(filmTitle) ){ //in the other films..
      
      if( filmsArray[i].ac.name.equals(ac.name) ){ //..containing the actor
        Particle p1 = new Particle(filmsArray[i].acs.name, 1, random(30, width/2-50), random(30, height/3) );
        p1.enlighted = true;
        engine.addParticle(p1, 0);
        engine.connectParticles(ac.name, p1.label, 0, 0);
        Particle p2 = new Particle(filmsArray[i].dir.name, 2, random (width/2+50, width-30), random(30, height/3 ));
        p2.enlighted = true;
        engine.addParticle(p2, 0);
        engine.connectParticles(ac.name, p2.label, 0, 0);
      }
      if( filmsArray[i].acs.name.equals(acs.name) ){ //..containing the actress
        Particle p1 = new Particle(filmsArray[i].ac.name, 0, random(width/2+50, width-30),  random(height*2/3+30, height-30) );
        p1.enlighted = true;
        engine.addParticle(p1, 1); 
        engine.connectParticles(acs.name, p1.label, 1, 1);
        Particle p2 = new Particle(filmsArray[i].dir.name, 2, random(30, width/2-50),random(height*2/3+30, height-30));
        p2.enlighted = true;
        engine.addParticle(p2, 1);
        engine.connectParticles(acs.name, p2.label, 1, 1);
      }
      if( filmsArray[i].dir.name.equals(d.name) ){ //..containing the director
        cd++;
        Particle p1 = new Particle(filmsArray[i].ac.name, 0, random(30, width/2-50), random(height/3+30, height*2/3-30) );
        p1.enlighted = true;
        engine.addParticle(p1, 2); 
        engine.connectParticles(d.name, p1.label, 2, 2);
        Particle p2 = new Particle(filmsArray[i].acs.name, 1,  random(width/2+50, width-30), random(height/3+30, height*2/3-30)  );
        p2.enlighted = true;
        engine.addParticle(p2, 2);
        engine.connectParticles(d.name, p2.label, 2, 2);
      }
    }
  }
}


